package sunwin.yois.web.common.controllerAspect;

import jodd.util.StringUtil;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import sunwin.yois.web.common.YoisAjaxAnswer;
import sunwin.yoms.comm.Domain;
import sunwin.yoms.comm.YomsException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by mt on 2015/7/29.
 */
@Component
@SuppressWarnings("unchecked")
public class YoisControllerAspect {
    /**
     * 在执行controller函数之前拦截
     *
     * @param joinPoint
     * @throws IllegalAccessException
     */
    public void before(JoinPoint joinPoint) throws IllegalAccessException {
        Object[] args = joinPoint.getArgs();

        setDomainBlankFieldAsNull(args);
    }

    /**
     * 手动拦截controller函数
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    public Object action(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Class iClass = method.getReturnType();

        //声明方法返回值
        Object result = null;
        Throwable exception = null;

        //开始执行方法
        try {
            result = joinPoint.proceed();
        } catch (Throwable ex) {
            exception = handleException(method, ex);
        }

        /*拦截并处理返回结果*/
        if (iClass != null) {
            if (iClass == ModelAndView.class) {
                return refactorModelAndView(result, exception);
            } else if (iClass == YoisAjaxAnswer.class) {
                return refactorYomsAjaxAnswer(result, exception);
            }
        }
        return result;
    }

    /**
     * 拦截Domain将字段为空白的String设置为null
     *
     * @param args
     */
    private void setDomainBlankFieldAsNull(Object[] args) {
        if (args != null) {
            for (Object arg : args) {
                try {
                    Domain domain = arg.getClass().getAnnotation(Domain.class);
                    if (domain != null) {
                        Field[] fields = arg.getClass().getDeclaredFields();
                        for (Field field : fields) {
                            if (field.getType() == String.class) {
                                boolean accessible = field.isAccessible();
                                field.setAccessible(true);
                                if (field.get(arg) != null && StringUtil.isBlank(field.get(arg) + "")) {
                                    field.set(arg, null);
                                }
                                field.setAccessible(accessible);
                            }
                        }
                    }
                } catch (Exception ex) {
                    continue;
                }
            }
        }
    }

    /**
     * 拦截YomsAjaxAnswer并重构
     * 如果返回对象为空则重新创建YomsAjaxAnswer对象并加入异常消息
     * 如果返回对象不为空则在原来的对象中加入异常消息
     *
     * @param result    函数返回对象
     * @param exception 异常
     * @return
     */
    private Object refactorYomsAjaxAnswer(Object result, Throwable exception) {
        if (result == null) {
            if (exception != null) {
                YoisAjaxAnswer yomsAjaxAnswer = new YoisAjaxAnswer();
                yomsAjaxAnswer.setException(exception.getMessage());
                result = yomsAjaxAnswer;
            }
        } else {
            if (exception != null) {
                ((YoisAjaxAnswer) result).setException(exception.getMessage());
            }
        }
        return result;
    }

    /**
     * 拦截ModelAndView并重构
     * 如果返回对象为空则重新创建ModelAndView对象并加入异常消息
     * 如果返回对象不为空则在原来的对象中加入异常消息
     *
     * @param result    函数返回对象
     * @param exception 异常
     * @return
     */
    private Object refactorModelAndView(Object result, Throwable exception) {
        if (result == null) {
            if (exception != null) {
                ModelAndView mav = new ModelAndView();
                mav.addObject("e", exception);
                result = mav;
            }
        } else {
            if (exception != null) {
                ((ModelAndView) result).addObject("e", exception);
            }
        }
        return result;
    }

    /**
     * 处理异常
     *
     * @param method
     * @param ex
     * @return
     */
    private Throwable handleException(Method method, Throwable ex) throws Throwable {
        Throwable exception = null;
        if (ex.getClass() == YomsException.class) {
            exception = ex;
            ex.printStackTrace();
        } else {
            Logger.getLogger(this.getClass()).error(ex.getMessage());
            throw ex;
        }
        return exception;
    }
}
